home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 039a / d3d.zip / D3D.C < prev    next >
C/C++ Source or Header  |  1991-08-30  |  62KB  |  2,249 lines

  1. /* D3D: Designing in Three Dimensions
  2.    After compilation, this module (D3D) is to be linked
  3.    together with the modules
  4.     GRPACK1
  5.    HLPFUN
  6.    TRAFO
  7.    The complier is Turbo C, Huge Memory Model
  8. */
  9. #include <stdio.h>
  10. #include <math.h>
  11. #include <ctype.h>
  12. #include <alloc.h>
  13. #include <conio.h>
  14. #include <string.h>
  15. #include <process.h>
  16. #include "grpack.h"
  17.  
  18. #include <dos.h>
  19.  
  20. #define  BIG   1e10
  21. #define  IBIG  30000
  22. #define  EPS   1e-6
  23. #define  MAXFACES 3000
  24. #define  LIN1  156
  25. #define  LIN2  168
  26. #define  LIN3  180
  27.  
  28. void
  29.  
  30.    initrotate(double a1, double a2, double a3,
  31.                   double v1, double v2, double v3,
  32.               double alpha),
  33.    rotate(double x,  double y, double z,
  34.           double *px1, double *py1, double *pz1),
  35.    init_viewport(void),
  36.    hlpfun(float rho, float theta, float phi, float surflimit),
  37.    coeff(float rho, float theta, float phi),
  38.    ermes(char *s);
  39.  
  40. int abs(int x);
  41.  
  42. static void
  43.    aspect(void),
  44.    getstr(int x, int y, char *str),
  45.    mv(float x, float y, float z),
  46.    dw(float x, float y, float z),
  47.    screencoor(int mode, int i, int *pX, int *pY),
  48.     viewing(float x, float y, float z,
  49.            double *pxe,double *pye,double *pze),
  50.    display(void),
  51.    plotpoint(int i, int Bold),
  52.    grmes(int meslin, char *s),
  53.    rdfile(int normal),
  54.    wrfile(void),
  55.    cursorcontrol(char direc),
  56.    cursor(float x, float y, float z, int new),
  57.    show(char c),
  58.    faces(void),
  59.    eyepos(void),
  60.    plotsph(float rho, float theta, float phi, int down),
  61.    enquire(int vpos, char *str, float *px),
  62.    textcursor(int col, int line),
  63.    checkfaces(int i),
  64.    infopage(int i),
  65.    helpinfo(void),
  66.    myungetch(char ch),
  67.    line3(int P, int Q),
  68.    checkall(void),
  69.    clear(void),
  70.    zoom(int large),
  71.    reposition(void),
  72.    plotaxes(int checksize),
  73.    fresh(void),
  74.     list_faces(void),
  75.     points(void),
  76.    transform(void),
  77.    check_alloc(int i),
  78.    asksave(void),
  79.    entire(void),
  80.    open_plotfile(void),
  81.    close_plotfile(void),
  82.    pressanykey(char *str);
  83.  
  84. static int
  85.    storepoint(int i, float x, float y, float z),
  86.    rdnumber(int *p),
  87.    rdoldnr(int *p),
  88.    getch1(void);
  89.  
  90. static char
  91.    query(int line, char *s),
  92.    mygetch(void);
  93.  
  94. struct linsegface
  95. {  int i;
  96.    double a, b, c;
  97.    struct linsegface *next;
  98. };
  99.  
  100. struct vertex
  101. {  int inuse;
  102.    float xw, yw, zw;
  103.    double xe, ye, ze;
  104.    struct linsegface *connect;
  105. } *p;
  106.  
  107. float xO, yO, zO;
  108.  
  109. double v11, v12, v13, v21, v22, v23, v31, v32, v33, v43,
  110.    PI, PIdiv180;
  111. float xmin, xmax, ymin, ymax;
  112.  
  113. static float c1, c2, d, c1first, c2first, dfirst,
  114.    rho, theta, phi, xxx,yyy,
  115.    Xvp_range, Yvp_range, Xvp_center, Yvp_center,
  116.    Xvp_min, Xvp_max, Yvp_min, Yvp_max,
  117.     xwmin, ywmin, zwmin, xwmax, ywmax, zwmax,
  118.    xcur, ycur, zcur, step=0.2, zemin, zemax;
  119.  
  120. static int margin, modified, faces_present,
  121.    zoomin, pridim, bufposition, inside, newcentralpoint,
  122.    numbers=1, num0, axes, axes0, auxlines=1, aux0,
  123.    bold=1, bold0, plength, psize, faces_entering,
  124.     points_entering, X__max1, progr_arg;
  125.  
  126. int nmax, **pface, nface, object_present;
  127.  
  128. static char buffer[50], s2[2], char_avail, filnam[40], spaces [60];
  129.  
  130. main(int argc, char *argv[])
  131. {
  132.    int i, lowest, highest;
  133.    long lbytes;
  134.    float threshold, surflimit, xlowest, xhighest;
  135.    char str[30], ch, ch0, ch1;
  136.    
  137.    if(argc > 1) {
  138.       strcpy(filnam, argv[1]);
  139.       progr_arg = 1;
  140.    }
  141.  
  142.     PI = 4.0 * atan(1.0);
  143.    PIdiv180 = PI/180.0;
  144.     pface = (int **)farcalloc(MAXFACES, sizeof(int *));
  145.    psize = sizeof(struct vertex);
  146.    lbytes = farcoreleft();
  147.    plength = lbytes/(3L * psize);
  148.    /*    About one third of free memory space is alloted to vertices */
  149.  
  150.    p = (struct vertex *)farcalloc(plength+7, psize);
  151.    if(p==NULL) ermes("Memory problem");
  152.    s2[1] = '\0';
  153.    margin = 456;
  154.    rho = 1000.0;
  155.    theta = 20.0;
  156.    phi = 75.0;
  157.    coeff(rho,theta,phi);
  158.    clearscr();
  159.    wrscr(1,0,"D3D: Designing in Three Dimensions");
  160.    wrscr(2,0,"==================================");
  161.    wrscr(4,0,"This program is the main subject of:");
  162.    wrscr(6,4,"Ammeraal, L. (1988), INTERACTIVE 3D COMPUTER GRAPHICS");
  163.    wrscr(7,4,"  Chichester: John Wiley & Sons. ");
  164.   
  165.     if(progr_arg) {
  166.       wrscr(16,0,"Do you want differences in line thicknesses? (Y/N): ");
  167.       settxtcursor(17,0);
  168.       ch=mygetch();
  169.       s2[0]=ch;
  170.       if(isalpha(ch)) wrscr(17,0,s2);
  171.       bold=(ch=='Y' || ch=='y');
  172.    }
  173.  
  174.    wrscr(19,0,"If you want help, press function key F1; otherwise,");
  175.    wrscr(20,0,"press any other key. (You may also press F1 for help later)");
  176.    settxtcursor(21,0);
  177.    ch=mygetch();
  178.    if(ch == 0 && getch() == 59 /*F1*/) helpinfo();
  179.     initgr();
  180.    X__max1 = X__max+1;
  181.    for(i=(X__max1 - margin - 16)/8;i>=0;i--)
  182.       spaces[i]=' '; /*String of spaces; '/0' at the end */
  183.    zoom(0);/* Set viewport constants; 0 = small viewport */   
  184.    clear();
  185.    display();
  186.     if(progr_arg) rdfile(0);
  187.  
  188.    /* Main Loop */
  189.    while
  190.    (grmes(LIN1, "Command:"), 
  191.    textcursor(margin+72, LIN1),
  192.    ch0=mygetch(), 
  193.    ch=toupper(ch0), ch != 'Q') {
  194.       grmes(LIN2, " ");
  195.       grmes(LIN3, " ");
  196.       if(ch0==0) {
  197.          ch1=mygetch();
  198.          if(ch1==59) /*F1*/ helpinfo();
  199.          continue;
  200.       }
  201.       show(ch);
  202.        if(isdigit(ch)) {
  203.          if(points_entering) {
  204.             myungetch(ch);
  205.             points();
  206.          }
  207.          else 
  208.          if(faces_entering) {
  209.             myungetch(ch);
  210.             faces();
  211.          }
  212.          else
  213.          grmes(LIN2,"Don't begin with digit");
  214.             continue;
  215.       }
  216.        if(ch=='I') {
  217.          points_entering = 1; 
  218.          points();
  219.          continue;
  220.       }
  221.       points_entering=0;
  222.       
  223.       if(ch=='F') {
  224.          faces_entering=1;
  225.          faces();
  226.          modified=1;
  227.          continue;
  228.       }
  229.       faces_entering=0;
  230.       
  231.       if(ch=='X' || ch=='Y' || ch=='Z') {
  232.             cursorcontrol(ch);
  233.          continue;
  234.       }
  235.         if(ch=='R') rdfile(1); else
  236.       if(ch=='W') { wrfile(); modified=0;} else
  237.       if(ch=='V') eyepos(); else
  238.         if(ch=='L') list_faces(); else
  239.       if(ch=='C') { *filnam='\0'; asksave(); clear(); display();} else
  240.       if(ch=='?') {
  241.          if(kbhit()) getch();
  242.          grmes(LIN2,"Point number:");
  243.             getstr(margin, LIN3, str);
  244.          if(sscanf(str,"%d", &i) !=1 || 1>=nmax || p[i].inuse ==0) {
  245.             grmes(LIN2,"Number or format wrong");
  246.             continue;
  247.          }
  248.          sprintf(str,"%4.2f %4.2f %4.2f",p[i].xw, p[i].yw, p[1].zw);
  249.             grmes(LIN3,str);
  250.       } else
  251.       if(ch=='D') {
  252.          if(kbhit())
  253.             getch();
  254.          while(nmax > 0 && p[nmax-1].inuse == 0)
  255.             nmax--;
  256.          xlowest = nmax;
  257.          enquire(LIN2, "Lower bound: ", &xlowest);
  258.          lowest = (int)(xlowest + 0.1);
  259.          if(lowest < 1)
  260.             lowest = 1;
  261.          xhighest = xlowest;
  262.          enquire(LIN3, "Upper bound: ", &xhighest);
  263.          highest = (int)(xhighest + 0.1);
  264.          if(highest >= nmax)
  265.             highest = nmax - 1;
  266.          if(lowest <= highest) {
  267.             for(i=lowest; i<=highest; i++) {
  268.                p[i].inuse = 0;
  269.                checkfaces(i);
  270.             }
  271.             checkall();
  272.             modified = 1;
  273.             display();
  274.          }
  275.       } else
  276.       if(ch=='M') {
  277.          numbers=(query(LIN1,"Point Numbers? (Y/N):")=='Y');
  278.          axes0=axes;
  279.          aux0=auxlines;
  280.          axes=(query(LIN1,"Axes? (Y/N):")=='Y');
  281.          if(axes)
  282.             auxlines=(query(LIN1,"Aux. lines? (Y/N):")=='Y');
  283.          else
  284.                 auxlines=0;
  285.          bold=(query(LIN1,"Bold lines? (Y/N):")=='Y');
  286.          if(axes0 && !axes || aux0 && !auxlines) checkall();
  287.          /* Adapt image size now that axes have been removed
  288.             and more room may have become avaliable for the 
  289.             image.
  290.          */
  291.          if(query(LIN1,"Entire screen? (Y/N):")=='Y') entire(); else
  292.          if(numbers !=num0 || axes !=axes0 || 
  293.             auxlines !=aux0  || bold != bold0) display(); 
  294.       } else
  295.       if(ch=='E') entire(); else
  296.       if(ch=='P') printgr(0.0,X__max,0.0,Y__max); else
  297.       if(ch=='S') enquire(LIN2,"Step size:",&step); else
  298.       if(ch=='T') transform(); else
  299.       if(ch=='H') {
  300.          clearpage();
  301.          to_text();
  302.          if(kbhit()) getch();
  303.          wrscr(0,0,"Do you want the object faces to approximate curved"
  304.          " surfaces (Y/N):");
  305.          settxtcursor(0,68);
  306.          ch=mygetch();
  307.          s2[0]=ch;
  308.          if(ch>32) wrscr(0,68,s2);
  309.          if(ch=='Y' || ch=='y') {
  310.             wrscr(2,0,"Enter 'threshold', in degrees. The"
  311.             " line of intersection of any");
  312.             wrscr(3,0,"two adjacent faces, if visable, will"
  313.             " be drawn only if the angle");
  314.             wrscr(4,0,"between the normal vectors of these"
  315.             " two faces is greater than");
  316.             wrscr(5,0,"'threshold'.  The default value 35 will"
  317.             " be used if you press only");
  318.             wrscr(6,0,"the enter key.");
  319.                 settxtcursor(6,15);
  320.             ch=getchar();
  321.                 if(ch=='\n' || (ungetc(ch,stdin), scanf("%f",&threshold) !=1))
  322.                threshold=35;
  323.             surflimit=cos(threshold*PIdiv180);
  324.          } 
  325.          else
  326.             surflimit=1.0;
  327.          initgr();
  328.          hlpfun(rho, theta, phi, surflimit);                
  329.          close_plotfile();
  330.          ch = mygetch();
  331.          if (ch=='P' || ch=='p')
  332.             printgr(0,X__max,0,Y__max);
  333.          if(pridim) {
  334.             clearpage();   
  335.             to_text();
  336.                 x_max=10.0;
  337.                 y_max=7.0;
  338.             pridim=0;
  339.             initgr();
  340.          }
  341.          display();
  342.       } else
  343.          grmes(LIN2,"Invalid command");            
  344.    }       
  345.    asksave();
  346.    to_text();
  347. }      
  348.          
  349. static void asksave(void)
  350. {
  351.    char ch;
  352.    if(modified && nmax + nface > 7) {
  353.       ch=query(LIN2,"Save object (Y/N): ");
  354.         if(ch=='Y' || ch=='y') wrfile();
  355.       grmes(LIN2," ");
  356.    }
  357. }
  358.  
  359. static void aspect()
  360. {
  361.    char ch;
  362.    wrscr( 7,0,"After displaying the results on the screen,"
  363.    " you can print");
  364.    wrscr( 8,0,"it on a matrix printer by giving the command P."
  365.    " (If, instead,");
  366.    wrscr( 9,0,"you press any other key, the previous"
  367.    " graphics screen will be");
  368.    wrscr(10,0,"restored.) As for printing, please note the"
  369.    " following:");
  370.    wrscr(11,0,"We say we are using the 'correct aspect"    
  371.    " ratio' if a");
  372.    wrscr(12,0,"circle is displayed as a real circle, not"
  373.    " as an ellipse.");
  374.    wrscr(13,0,"Normally, the aspect rationwill be correct"
  375.    " on the screen.");
  376.    wrscr(14,0,"If you want a correct aspect"
  377.    " ratio on the printer");
  378.    wrscr(15,0,"(accepting an incorrect aspect ratio on the"
  379.    " screen), then");
  380.    wrscr(16,0,"please enter A. Instead, you can enter the"
  381.    " letter O if you");
  382.    wrscr(17,0,"want an output file (xxx.PLT), which, for"
  383.    " example, can be");
  384.    wrscr(18,0,"read by program plothp to produce output on"
  385.    " a HP plotter.");
  386.    wrscr(19,0,"If neither is desirable, press"
  387.    " any other key...");
  388.    settxtcursor(20,0);
  389.     ch = mygetch();
  390.    s2[0] = ch;
  391.    if(ch > ' ') wrscr(20,0,s2);
  392.    if(ch == 'A' || ch == 'a') {
  393.       setprdim();
  394.       pridim = 1;
  395.    }
  396.    else  
  397.       if(ch == 'O' || ch == 'o') open_plotfile();
  398. }
  399.  
  400. static void checkall(void)
  401. /* shrink, if required, after point deletion */
  402. {
  403.    int i, count=0;
  404.    float xw, yw, zw, ze;
  405.    xwmin = ywmin = zwmin = zemin = BIG;
  406.    xwmax = ywmax = zwmax = zemax = -BIG;
  407.     for(i=1; i<nmax; i++)
  408.    if(p[i].inuse) {
  409.       count++;
  410.       xw = p[i].xw;
  411.       yw = p[i].yw;
  412.       zw = p[i].zw;
  413.       ze = p[i].ze;
  414.       if(xw < xwmin) xwmin = xw;
  415.       if(xw > xwmax) xwmax = xw;
  416.       if(yw < ywmin) ywmin = yw;
  417.       if(yw > xwmax) xwmax = yw;
  418.       if(zw < zwmin) zwmin = zw;
  419.       if(zw > zwmax) zwmax = zw;
  420.       if(ze < zemin) zemin = ze;
  421.       if(ze > zemax) zemax = ze;
  422.    }      
  423.    if(count == 0) 
  424.         clear();
  425.    else {
  426.       /* to avoid axes of length 0 */
  427.       if(xwmax <0.5) xwmax = 0.5;
  428.       if(ywmax <0.5) ywmax = 0.5;
  429.       if(zwmax <0.5) zwmax = 0.5;
  430.       xO = BIG;
  431.       /* Forces 'reposition' to compute a new central object point */
  432.       reposition();
  433.    }
  434. }
  435.  
  436. static void check_alloc(int i)
  437. {
  438.    if(i>plength) ermes("Vertex number too high");
  439. }
  440.  
  441. static void checkfaces(int i)
  442. {  /* Point i has just been deleted.  If any faces have i as
  443.       a vertex, then these faces are deleted as well.       */
  444.    int j, n, k;
  445.    if(nface == 0)
  446.       return;
  447.    grmes(LIN3, "Please wait ...");
  448.    for(j=0; j<nface; j++) {
  449.       if(pface[j] == NULL)
  450.          continue;
  451.       n = pface[j][0];
  452.       if(n < 0)
  453.          ermes("n<0 in checkfaces");
  454.       for(k=1; k<=n; k++)
  455.       if(abs(pface[j][k]) == i) {
  456.          farfree(pface[j]);
  457.          pface[j] = NULL;
  458.          break;
  459.         }
  460.    }
  461.    grmes(LIN3, " ");
  462. }
  463.          
  464.  
  465. static void clear(void)
  466. {
  467.    static int first=1;
  468.    int i,j;
  469.  
  470.    axes = auxlines = numbers = 1;
  471.    for(i=0; i<nmax; i++)
  472.       p[i].inuse = 0;
  473.    p[0].xw = p[0].yw = p[0].zw = 0.0;
  474.    nmax = 1;
  475.  
  476.    for(j=0; j<nface; j++)
  477.    if(pface[j] != NULL) {
  478.       farfree(pface[j]);
  479.       pface[j] = NULL;
  480.    }
  481.    
  482.    nface = 0;
  483.    xwmin = ywmin = zwmin = 0.0;
  484.    xwmax = ywmax = zwmax = 1.0;
  485.    xO = yO = zO = 0.5;
  486.    fresh();
  487.    reposition();
  488.    if(first) {
  489.       c1first = c1;
  490.       c2first = c2;
  491.       dfirst = d;
  492.       first = 0;
  493.    }
  494.     modified = 0;
  495.    object_present = 0;
  496. }
  497.  
  498. static void close_plotfile(void)
  499. {
  500.    if(fplot != NULL) {
  501.       fclose(fplot);
  502.         fplot = NULL;
  503.     }
  504. }
  505.  
  506. static void cursor(float xw, float yw, float zw, int new)
  507. {
  508.    extern int drawmode;
  509.    int i, j, dm, cnt;
  510.    static int X, Y, X0, Y0;
  511.    if(new) {
  512.       inside = 1;
  513.       for(cnt=0; cnt<2; cnt++) {
  514.          storepoint(nmax+4, xw, yw, zw);
  515.          storepoint(nmax+5, xw, yw, 0.0);
  516.          screencoor(1, nmax+4, &X, &Y);
  517.          screencoor(1, nmax+5, &X0, &Y0);
  518.          if(inside) 
  519.             break;
  520.          else {
  521.             reposition();
  522.             display();
  523.          }
  524.       }
  525.       if(cnt == 2) ermes("cnt = 2 in cursor");
  526.       p[nmax+4].inuse = 0;
  527.       p[nmax+5].inuse = 0;
  528.    }
  529.     dm = drawmode;
  530.    drawmode = 0;
  531.     for(j=-2;j<=2;j+=4)
  532.         for(i=-4;j<=4;j++)
  533.          dot(X+i,Y+j);
  534.  
  535.    dot(X-4,Y-1);
  536.    dot(X-3,Y-1);
  537.    dot(X+3,Y-1);
  538.    dot(X+4,Y-1);
  539.  
  540.    dot(X-4,Y);
  541.    dot(X-3,Y);
  542.    dot(X+3,Y);
  543.    dot(X+4,Y);
  544.  
  545.    dot(X,Y);
  546.  
  547.    dot(X-4,Y+1);
  548.    dot(X-3,Y+1);
  549.    dot(X+3,Y+1);
  550.    dot(X+4,Y+1);
  551.    
  552.    draw_line(X,Y,X0,Y0);
  553.    drawmode = dm;
  554. }
  555.  
  556. static void cursorcontrol(char direc)
  557. {
  558.    char c, c0, str[30];
  559.    float *axis, x0, y0, z0, dx, dy, dz, dist2, d2;
  560.    int i, j, jumped = 0;
  561.    if(!auxlines) {
  562.       axes = auxlines = 1;
  563.       display();
  564.     }
  565.    xcur = ycur = zcur = 0.0;
  566.    cursor(xcur, ycur, zcur, 1);
  567.    axis = (direc == 'X' ? &xcur: direc == 'Y' ? &ycur : &zcur);
  568.    grmes(LIN2, "Press +, -, I, J, or D");
  569.    grmes(LIN3, "(or press Enter)");
  570.    while(c0 = mygetch(), c = toupper(c0), 
  571.    c == '+' || c == '-' || 
  572.    c == 'X' || c == 'Y' || c == 'Z' ||
  573.    c == 'I' || c == 'J' || c == 'D' ||
  574.    c == 0) {
  575.       if(c != 'D') jumped = 0;
  576.       if(c == '+' || c == '-') {
  577.          x0 = xcur;
  578.          y0 = ycur;
  579.             z0 = zcur;
  580.             if(c == '-')
  581.                 *axis -= step;
  582.             else
  583.                 *axis += step;
  584.          cursor(x0, y0, z0, 0);
  585.          cursor(xcur, ycur, zcur, 1);
  586.          sprintf(str, "%5.2f %5.2f %5.2f   ",xcur, ycur, zcur);
  587.          grmes(LIN3, str);
  588.          continue;
  589.       }
  590.       show(c);
  591.       if(c == 'X') {axis = &xcur; direc = c;} else
  592.       if(c == 'Y') {axis = &ycur; direc = c;} else
  593.       if(c == 'Z') {axis = &zcur; direc = c;} else
  594.       if(c == 'I') {
  595.             for(i=1; i<plength; i++) if (p[i].inuse == 0) break;
  596.          check_alloc(i);
  597.          if(i >= nmax) nmax = i+1;
  598.          cursor(xcur, ycur, zcur, 0);        /* Delete */
  599.             storepoint(i, xcur, ycur, zcur);
  600.          modified = 1;
  601.          plotpoint(i,1);
  602.          cursor(xcur, ycur, zcur, 0);        /* Draw again */
  603.       }
  604.       else
  605.         if(c == 'J') {
  606.          if(nmax == 0) {
  607.             grmes(LIN2, "No points present");
  608.             cursor(xcur, ycur, zcur, 0);
  609.             grmes(LIN3, " ");
  610.             return;
  611.          }
  612.          dist2 = BIG;
  613.          for(i=1; i<nmax; i++)
  614.          if(p[i].inuse) {
  615.             dx = p[1].xw - xcur;
  616.             dy = p[1].yw - ycur;
  617.             dz = p[1].zw - zcur;
  618.             d2 = dx*dx + dy*dy + dz*dz;
  619.             if(d2 < dist2) {
  620.                dist2 = d2;
  621.                j = i;
  622.             }
  623.          }
  624.          jumped = 1;
  625.          cursor(xcur, ycur, zcur, 0);       /* Delete old cursor */
  626.          xcur = p[j].xw;
  627.          ycur = p[j].yw;
  628.          zcur = p[j].zw;
  629.          cursor(xcur, ycur, zcur, 1);
  630.          sprintf(str, "%4d %4.2f %4.2f %4.2f", j, xcur, ycur, zcur);
  631.          grmes(LIN3, str);
  632.       }
  633.       else
  634.         if(c == 'D') {
  635.          if(!jumped)
  636.             grmes(LIN3, "Use J first");
  637.          else {
  638.             p[j].inuse = 0;
  639.             cursor(xcur, ycur, zcur, 0);
  640.             checkfaces(j);
  641.             checkall();
  642.             modified = 1;
  643.             jumped = 0;
  644.             display();
  645.             cursor(xcur, ycur, zcur, 1);
  646.             grmes(LIN2,"Press +, -, I, J, ?, D");
  647.             grmes(LIN3,"(or press Enter)");
  648.          }
  649.       }
  650.       else {                  /* c == 0: Probably arrow key pressed */
  651.          if(getch() == 59)
  652.                 helpinfo();
  653.          else
  654.             grmes(LIN3, "Wrong key pressed");
  655.       }
  656.       show(direc);
  657.    }
  658.    cursor(xcur, ycur, zcur, 0);
  659.    if(c0 != '\n' && c0 != '\r') myungetch(c0);
  660.    show(' ');
  661.    grmes(LIN2, " ");
  662.    grmes(LIN3, " ");
  663. }
  664.  
  665. static void display(void)
  666. {
  667.    int i, j, k, n, drawn, i_old;
  668.    faces_present=0;
  669.    clearpage();
  670.    if(axes) plotaxes(1);
  671.    if(zoomin) 
  672.       init_viewport();     /* Defined in module HLPFUN */
  673.    else {
  674.       imove(0,0);
  675.       idraw(X__max,0);
  676.       idraw(X__max,Y__max);
  677.         idraw(0,Y__max);
  678.         idraw(0,0);
  679.       imove(margin-4, 0);
  680.       idraw(margin-4, Y__max);
  681.         textXY(margin,   5, "D3D");
  682.       textXY(margin,  20, "Available commands:");
  683.       textXY(margin,  34, "X/Y/Z: Cursor control");
  684.       textXY(margin,  46, "?: Show coordinates");
  685.       textXY(margin,  58, "Mode (Axes etc.)");
  686.       textXY(margin,  70, "F1 (Help)  | Quit");
  687.       textXY(margin,  82, "Step       | Clear");
  688.       textXY(margin,  94, "Insert     | Delete");
  689.       textXY(margin, 106, "Faces      | List");
  690.       textXY(margin, 118, "Read       | Write");
  691.       textXY(margin, 130, "Entire     | Hidden");
  692.       textXY(margin, 142, "Viewpoint  | Transform");
  693.       grmes(LIN3, "Please wait...");
  694.    }
  695.     for(j=0; j<nface; j++) {
  696.       if(pface[j] == NULL) continue;
  697.         faces_present = 1;            /* See 'list_faces' */
  698.       i_old = abs(pface[j][1]);
  699.       n = pface[j][0];
  700.       if (n<0) ermes("n<0 in display");
  701.       for(k=2; k<=n; k++) {
  702.          i = pface[j][k];
  703.          drawn = i >= 0;
  704.          i = abs(i);
  705.          if(drawn) line3(i_old, i);
  706.          i_old = i;
  707.       }
  708.       i = pface[j][1];
  709.       drawn = i >= 0;
  710.       i = abs(i);
  711.       if(drawn) line3(i_old, i);
  712.    }
  713.    for( i=1; i<nmax; i++)
  714.    if(p[i].inuse)
  715.       plotpoint(i,0);
  716.    if(!zoomin) {
  717.       grmes(LIN1, "Command:");
  718.       grmes(LIN3, " ");
  719.       num0 = numbers;
  720.       axes0 = axes;
  721.       aux0 = auxlines;
  722.       bold0 = bold;
  723.    }
  724.    if(axes) plotaxes(0);
  725.    /* Only to make letters x, y, z, legible */
  726. }
  727.  
  728. static void dw(float x, float y, float z)
  729. {
  730.    int X,Y;
  731.    double xe, ye, ze;
  732.    viewing(x-0.5, y-0.5, z-0.5, &xe, &ye, &ze);
  733.    /* xO = yO = zO = 0.5 */
  734.    X = IX(d*xe/ze+c1);
  735.    Y = IY(d*ye/ze+c2);
  736.    idraw(X,Y);
  737. }
  738.  
  739. static void enquire(int vpos, char *str, float *px)
  740. {
  741.     char snum[40], dum[40];
  742.     int len, slen, j;
  743.     char ch;
  744.  
  745.    if(kbhit()) getch();
  746.    len = 8*strlen(str);
  747.    if(margin+len > X__max1)
  748.       ermes("String too long to 'enquire'");
  749.    textXY(margin, vpos, str);
  750.    sprintf(snum, "%3.1f", *px);
  751.    slen = strlen(snum);
  752.    if(snum[slen-1] == '0' && snum[slen-2] == '.')
  753.       snum[slen-2] = '\0';
  754.     if(margin+len+8*strlen(snum) > X__max1)
  755.       ermes("String plus number too long to 'enquire'");
  756.    slen = (X__max - margin - len)/8;
  757.    for(j=0; j<slen; j++) dum[j] = ' ';
  758.  
  759.    dum[slen] = '\0';
  760.    do {
  761.       j = 100;
  762.       do textXY(margin+len, vpos, dum);
  763.          while(--j && !kbhit());
  764.       j=200;
  765.       do textXY(margin+len, vpos, snum);
  766.          while(--j && !kbhit());
  767.    }
  768.    while (!kbhit());
  769.    ch = mygetch();
  770.    if(ch == 0) {
  771.       ch = mygetch();
  772.       if(ch == 59) {     /* F1 key */
  773.          helpinfo();
  774.          textXY(margin+len, vpos, dum);
  775.       }
  776.       else
  777.       if(ch == 3) {   /* Break */
  778.          to_text();
  779.          exit(1);
  780.       }
  781.    }
  782.    else
  783.    if(ch == '\n' || ch == '\r') 
  784.       return;
  785.    else
  786.       myungetch(ch);
  787.    while(1) {
  788.       getstr(margin+len, vpos, snum);
  789.         if(sscanf(snum, "%f", px) == 1) break;
  790.       textXY(margin+len, vpos, dum);
  791.    }
  792. }
  793.  
  794. static void entire(void)  /* Use entire screen */
  795. {
  796.    float c1save, c2save, dsave;
  797.    char ch;
  798.  
  799.    c1save = c1; 
  800.    c2save = c2;
  801.    dsave = d;
  802.    clearpage();
  803.    to_text();
  804.    if(kbhit()) 
  805.       getch();
  806.    initgr();            /* Computes horfact and vertfact       */
  807.    zoom(1);             /* Changes Xvp_max etc.                */
  808.    newcentralpoint = 0; /* May also change central point       */
  809.    reposition();        /* Compute new c1, c2 and d            */
  810.    display();           /* Show large picture                  */
  811.    close_plotfile();
  812.    ch = mygetch();
  813.    if(ch == 'P' || ch == 'p')
  814.       printgr(0, X__max, 0, Y__max);
  815.    clearpage();
  816.    to_text();
  817.     if(pridim) {
  818.       x_max = 10;
  819.       y_max = 7.0;
  820.       pridim = 0;
  821.    }
  822.    initgr();
  823.    zoom(0);
  824.    if(newcentralpoint)
  825.       reposition();
  826.    else {
  827.       c1 = c1save;
  828.       c2 = c2save;
  829.       d  = dsave;
  830.    }
  831.    display();
  832. }
  833.  
  834. void ermes(char *s)
  835. {
  836.    char ch;
  837.    if(in_textmode) {
  838.       printf(s);
  839.       exit(1);
  840.    }
  841.    to_text();
  842.    printf(s);
  843.    if(!modified || nmax + nface <=7)
  844.       exit(1);
  845.    printf("\n\nD3D will stop execution.\n");
  846.    printf("Do you want to save the object? (Y/N): ");
  847.    ch = getche();
  848.    if(ch == 'Y' || ch == 'y') {
  849.       initgr();
  850.       wrfile();
  851.       to_text();
  852.    }
  853.    exit(1);
  854. }
  855.  
  856. static void eyepos(void)
  857. {
  858.    float rho_1, theta_1, phi_1, rho1, theta1, phi1, dtheta, dphi, rho2;
  859.    int i, n = 5;
  860.    rho_1 = rho;
  861.    theta_1 = theta;
  862.    phi_1 = phi;
  863.    rho = 1000;
  864.    theta = 20;
  865.    phi = 75;
  866.    coeff(rho, theta, phi);
  867.    clearpage();
  868.    c1 = c1first;
  869.    c2 = c2first;
  870.    d  = dfirst;
  871.    mv(0.0, 0.0, 0.0); dw(1.0, 0.0, 0.0); text("x");
  872.    mv(0.0, 0.0, 0.0); dw(0.0, 1.0, 0.0); text("y");
  873.    mv(0.0, 0.0, 0.0); dw(0.0, 0.0, 1.0); text("z");
  874.    mv(0.0, 0.0, 0.0); 
  875.    rho1 = 1.0;
  876.    theta1 = 40;
  877.    phi1 = 40;
  878.    rho2 = rho1*sin(theta1*PIdiv180);
  879.    plotsph(rho2, theta1, 90.0, 1);
  880.    plotsph(rho1, theta1, phi1, 1);
  881.    dw(0.0, 0.0, 0.0);
  882.    rho = 0.9;
  883.     dtheta = theta1/n;
  884.    rho2 = 0.9*rho2;
  885.    mv(rho2, 0.0, 0.0);
  886.    for(i=1; i<n; i++)
  887.       plotsph(rho2, i*dtheta, 90.0, 1);
  888.    dphi = phi1/n;
  889.    plotsph(rho1, 0.0, 0.0, 0);
  890.    for(i=1; i<n; i++)
  891.       plotsph(rho1, theta1, i*dphi, 1);
  892.    plotsph(0.5*rho1, theta1, phi1, 0);
  893.    text("rho");
  894.    plotsph(rho2,0.4*theta1, 90.0, 0);
  895.    text("theta");
  896.    plotsph(rho1, theta1, 0.4*phi1, 0);
  897.    text("phi");
  898.    plotsph(1.2*rho1, theta1, phi1, 0);
  899.    text("Eye");
  900.    textXY(margin, 15, "Enter rho, theta, phi");
  901.    textXY(margin, 30, "(theta, rho in degr.)");
  902.    textXY(margin, 45, "If you press Enter, ");
  903.     textXY(margin, 60, "the values displayed");
  904.    textXY(margin, 75, "will be used.");
  905.    enquire(90, "rho   = ", &rho_1);
  906.    enquire(105,"theta = ", &theta_1);
  907.    enquire(120,"phi   = ", &phi_1);
  908.    rho = rho_1;
  909.    theta = theta_1;
  910.    phi = phi_1;
  911.    coeff(rho, theta, phi);
  912.    xO = BIG;
  913.    /* Forces 'reposition to compute a new central object point */
  914.    reposition();
  915.    display();
  916. }
  917.  
  918. static void faces(void)
  919. {
  920.    int i, n=0, draw, i_old=0;
  921.    char str[30];
  922.     double xA, yA, zA,xB, yB, zB, xC, yC, zC, a, b, c, h;
  923.    if((pface[nface] = (int *)farcalloc(5, sizeof(int))) == NULL)
  924.       ermes("Not enough memory");
  925.    grmes(LIN2, "Nrs. closed by period:");
  926.    textcursor(margin, LIN3);
  927.    bufposition = -1;
  928.    while(1) {
  929.       if(rdnumber(&i) == 0) 
  930.          break;
  931.       draw = i >= 0;
  932.       i = abs(i);
  933.       n++;
  934.         if(p[i].inuse == 0) {
  935.             sprintf(str, "Undef. point: %6d", i);
  936.          pressanykey(str);
  937.          display();
  938.          faces_entering = 0;
  939.          return;
  940.       }
  941.       if(n == 1) {
  942.          xA = p[i].xw;
  943.             yA = p[i].yw;
  944.          zA = p[i].zw;
  945.       }
  946.       else if(n == 2) {
  947.          xB = p[i].xw;
  948.             yB = p[i].yw;
  949.          zB = p[i].zw;
  950.       }
  951.       else if(n == 3) {
  952.          xC = p[i].xw;
  953.             yC = p[i].yw;
  954.          zC = p[i].zw;
  955.  
  956.          h = xA * (yB*zC - yC*zB) -
  957.              xB * (yA*zC - yC*zA) +
  958.              xC * (yA*zB - yB*zA);
  959.  
  960.          a =   yA * (zB - zC) -
  961.                yB * (zA - zC) +
  962.                yC * (zA - zB);
  963.  
  964.          b = -(xA * (zB - zC) -
  965.                xB * (zA - zC) +
  966.                xC * (zA - zB));
  967.  
  968.          c =   xA * (yB - yC) -
  969.                xB * (yA - yC) +
  970.                xC * (yA - yB);
  971.       }
  972.       else if(fabs(a*p[i].xw + 
  973.                    b*p[i].yw + 
  974.                    c*p[i].zw - h) > 0.001*fabs(h) + EPS) {
  975.          pressanykey("Not in the same plane");
  976.          display();              /* remove any wrong lines */
  977.          faces_entering = 0;
  978.          return;
  979.       }
  980.       if(n > 1 && draw)
  981.          line3(i_old, i);
  982.       i_old = i;
  983.       if(n > 4) {
  984.          if((pface[nface] = 
  985.             (int *) farrealloc(pface[nface], (n+1)*sizeof(int))) == NULL)
  986.             ermes("Not enough memory");
  987.       }
  988.       pface[nface][n] = (draw ? i : -i);
  989.    }
  990.    if(n == 0) {
  991.       grmes(LIN2, "Invalid integer");
  992.       farfree(pface[nface]);
  993.       faces_entering = 0;
  994.       return;
  995.    }
  996.    i = pface[nface][1];
  997.    if(i >= 0)
  998.       line3(i_old, i);
  999.    pface[nface][0] = n;
  1000.    nface++;
  1001.    if(nface == MAXFACES) {
  1002.       grmes(LIN2, "Too many faces #1");
  1003.       nface--;
  1004.    }
  1005. }
  1006.  
  1007. static void fresh(void)
  1008. {
  1009.    int i , X, Y;
  1010.    xmin = ymin = zemin =  BIG;
  1011.     xmax = ymax = zemax = -BIG;       /* to be updated */
  1012.  
  1013.    /* Compute xmin, xmax, ymin, ymax: */
  1014.  
  1015.    storepoint(nmax,     0.0,   0.0,   0.0);
  1016.    storepoint(nmax+1, xwmax,   0.0,   0.0);
  1017.    storepoint(nmax+2,   0.0, ywmax,   0.0);
  1018.    storepoint(nmax+3,   0.0,   0.0, zwmax);
  1019.    screencoor(0, nmax,   &X, &Y);
  1020.    screencoor(0, nmax+1, &X, &Y); 
  1021.    screencoor(0, nmax+2, &X, &Y); 
  1022.    screencoor(0, nmax+3, &X, &Y); 
  1023.     for(i=nmax; i<nmax+4; i++)
  1024.       p[i].inuse = 0;
  1025. }
  1026.  
  1027. static int getch1(void)             /* Only called by rdnumber */
  1028. {
  1029.    char ch;
  1030.  
  1031.    if(bufposition < 0) {
  1032.       getstr(margin, LIN3, buffer);
  1033.       bufposition = 0;
  1034.    }
  1035.    ch = buffer[bufposition++];
  1036.    if(8*bufposition >= X__max1 - margin) {
  1037.         getstr(margin, LIN3, buffer);
  1038.       ch = buffer[0];
  1039.       bufposition = 1;
  1040.    }
  1041.    else if(ch == '\0') {
  1042.       bufposition = -1;
  1043.         ch = '\n';
  1044.    }
  1045.    return ch;
  1046. }
  1047.  
  1048. static void getstr(int X, int Y, char *str)
  1049. {
  1050.    char ch;
  1051.    int i=0, first = 1, j, k;
  1052.    while(1) {
  1053.       j = X + 8*i;
  1054.       if(j >= X__max1 - 8)
  1055.          break;
  1056.       if(first) {
  1057.          for(k=X; k<X__max1 - 8; k+=8)
  1058.             textXY(k, Y, " ");
  1059.          first = 0;
  1060.       }
  1061.       textcursor(j, Y);
  1062.       ch = mygetch();
  1063.       if(ch == '\n' || ch == '\r') 
  1064.          break;
  1065.       if(ch == 8) {     /* backspage */
  1066.          if(--i < 0) 
  1067.             i = 0;
  1068.       }
  1069.       else {
  1070.          str[i] = s2[0] = ch;
  1071.          textXY(j, Y, s2);
  1072.          i++;
  1073.       }
  1074.    }
  1075.    str[i] = '\0';
  1076. }
  1077.  
  1078. static void grmes(int meslin, char *s)
  1079. {
  1080.    int len;
  1081.  
  1082.    len = 8 * strlen(s);
  1083.    if(!in_textmode) {
  1084.       textXY(margin, meslin, spaces);
  1085.       if(margin + len > X__max1) {
  1086.          to_text();
  1087.          printf("In grmes:\n");
  1088.          printf("s='%s' len=%d margin=%d", s, len, margin);
  1089.          exit(1);
  1090.       }
  1091.       textXY(margin, meslin, s);
  1092.    }
  1093.    else
  1094.         printf("%s\n", s);
  1095. }
  1096.  
  1097. static void helpinfo(void)
  1098. {
  1099.    int i=1, was_in_grmode;
  1100.  
  1101.    was_in_grmode = !in_textmode;
  1102.    settxtcursor(24, 37);
  1103.    if(was_in_grmode) {
  1104.       clearpage();
  1105.       to_text();
  1106.    }
  1107.    do {
  1108.       infopage(i);
  1109.       if(i == 1)
  1110.          wrscr(24, 0, "Press any key to continue ...");
  1111.       else {
  1112.          wrscr(23,0,
  1113.             "Press 'arrow up' for the previous info page,");
  1114.          wrscr(24,0,
  1115.             "or any other key to continue ...");
  1116.       }
  1117.       if(mygetch() == 0 && mygetch() == 72) {
  1118.          if(--i == 0) 
  1119.             i = 1;
  1120.       }
  1121.       else i++;
  1122.    }
  1123.    while (i < 4);
  1124.    if(was_in_grmode) {
  1125.       initgr();
  1126.       display();
  1127.    }
  1128. }
  1129.  
  1130. static void infopage(int i)
  1131. {
  1132.    if(i == 1) {
  1133.       clearscr();
  1134.       wrscr( 0, 68, "Info page 1");
  1135.       wrscr( 1, 68, "(of 3 pages)");
  1136.       wrscr( 2, 0, "D3D: Designing in Three Dimensions,");
  1137.       wrscr( 3, 0, "by L. Ammeraal");
  1138.       wrscr( 5, 0, "Program D3D enables you to produce"
  1139.                    " realistic images of 3D objects,");
  1140.       wrscr( 6, 0, "The easiest way to do this is using a file"
  1141.                    " prepared by this very");
  1142.       wrscr( 7, 0, "program or by any other means.  Instead, you"
  1143.                    " can begin without ");
  1144.       wrscr( 8, 0, "any input file, and define points yourself"
  1145.                    " by using command I,");
  1146.       wrscr( 9, 0, "either immediately or under cursor control."
  1147.                    " In the former case, ");
  1148.       wrscr(10, 0, "command I is followed by entering a"
  1149.                    " nonnegative integer n and the ");
  1150.       wrscr(11, 0, "3D coordinates x, y, z of the new point. In"
  1151.                    " the latter case, a cursor");
  1152.       wrscr(12, 0, "is used to define the position of a point."
  1153.                    " You can simply press one");
  1154.       wrscr(13, 0, "of the keys X, Y, Z, followed by + or"
  1155.                    " - to move the cursor. Under");
  1156.       wrscr(14, 0, "cursor control, command I inserts a new"
  1157.                    " point, and command J causes the");
  1158.       wrscr(15, 0, "cursor to jump to nearest existing"
  1159.                    " point. You give the command S");
  1160.       wrscr(16, 0, "to change the step size for cursor"
  1161.                    " movements. To display the coordinates");
  1162.       wrscr(17, 0, "of a point, enter its number preceded"
  1163.                          " by a question mark. With");
  1164.       wrscr(18, 0, "command D you can delete all points"
  1165.                    " with numbers lying in a given");
  1166.       wrscr(19, 0, "range; in cursor-control mode, D deletes"
  1167.                    " only one point, selected by J.");
  1168.       wrscr(20, 0, "Mode command M is used to display or omit"
  1169.                    " point numbers, axes, vertical");
  1170.       wrscr(21, 0, "projection lines, and control line"
  1171.                    " thickness and screen size");
  1172.    }
  1173.    else if (i == 2) {
  1174.       clearscr();
  1175.       wrscr( 0, 68,"Info page 2");
  1176.       wrscr( 1, 68,"(of 3 pages)");
  1177.       wrscr( 2, 0, "After having entered some points, you can"
  1178.                    " define faces and draw");  
  1179.       wrscr( 3, 0, "lines by using command F, followed by point"
  1180.                    " numbers and then");
  1181.       wrscr( 4, 0, "followed by a period (.), as, for"  
  1182.                    " example, in:");
  1183.       wrscr( 5, 0, "   F");
  1184.         wrscr( 6, 0, "   1 2 3 4 5.");
  1185.       wrscr( 7, 0, "If F is followed by more than two point"
  1186.                    " numbers, then these must"); 
  1187.       wrscr( 8, 0, "be the vertices of a polygon, all lying in"
  1188.                    " the same plane, see");
  1189.       wrscr( 9, 0, "also command R. After command H, see below"
  1190.                    " these polygons will");
  1191.       wrscr(10, 0, "act as bounding faces of a"
  1192.                    " three dimensional object; the vertices");
  1193.       wrscr(11, 0, "must be given in counter-clockwise order"
  1194.                    " (viewed from the outside");
  1195.       wrscr(12, 0, "of the object). Any mistakes with command F"
  1196.                    " can be corrected by");
  1197.       wrscr(13, 0, "command L. Command R reads the object from"
  1198.                    " a file, and command W");
  1199.       wrscr(14, 0, "writes it to a file. To change the"
  1200.                    " viewpoint, use command V.");
  1201.       wrscr(15, 0, "Automatic hidden-line elimination is"
  1202.                    " performed by command H.");
  1203.       wrscr(16, 0, "By choosing the requested value 'threshold'"
  1204.                    " greater than 0, you");
  1205.       wrscr(17, 0, "can make two adjacent faces (with the"
  1206.                    " dihedral angle of almost 180");
  1207.       wrscr(18, 0, "degrees) approximate a curved surface."
  1208.                    " The intersecting edge");
  1209.       wrscr(19, 0, "of two such faces is draawn only if"
  1210.                    " the angle between their");
  1211.       wrscr(20, 0, "normal vectors is greater than the"
  1212.                    " given 'threshold'. Command E");
  1213.       wrscr(21, 0, "causes the entire screen to be used for"
  1214.                    " the image. Command E and");
  1215.       wrscr(22, 0, "H can also give printer"
  1216.                    " and plotter output.");
  1217.    }
  1218.    else if (i == 3) {
  1219.       clearscr();
  1220.       wrscr( 0, 68,"Info page 3");
  1221.       wrscr( 1, 68,"(of 3 pages)");
  1222.       wrscr( 2, 0, "There are some accompanying files, called"
  1223.                          " EXAMPLE.DAT, etc., which");
  1224.       wrscr( 3, 0, "show the structure of 'object files',"
  1225.                    " written by command W and read");
  1226.       wrscr( 4, 0, "by command R. First, all relevant points"
  1227.                    " are given in the form");
  1228.       wrscr( 5, 0, "n x y z, where n is the point number. Then"
  1229.                          " the keyword 'Faces:' may");
  1230.       wrscr( 6, 0, "follow, to introduce sequences of point"
  1231.                    " numbers, see also command F.");
  1232.       wrscr( 7, 0, "Each sequence is followed by a period (.),"
  1233.                    " or by the character #. The");
  1234.       wrscr( 8, 0, "points given in each sequence are the"
  1235.                    " vertices of a polygon, which");
  1236.       wrscr( 9, 0, "after command H, acts as a bounding face."
  1237.                    " The sides of such polygons");
  1238.       wrscr(10, 0, "are line segments to be drawn, if visible"
  1239.                    " except for negative point");
  1240.       wrscr(11, 0, "numbers. For example, in '8 3 -5 2 7.',"
  1241.                    " side 35, even if visible, is not");
  1242.       wrscr(12, 0, "to be drawn. A sequence of only two"
  1243.                    " points denotes a loose line segment.");
  1244.       wrscr(13, 0, "Command T offers four types of"
  1245.                    " transformations, namely rotation");
  1246.       wrscr(14, 0, "translation, scaling and reflection.");
  1247.       wrscr(16, 0, "The simplest way to begin is using the command"
  1248.                    " R to read a given");
  1249.       wrscr(17, 0, "file, such as EXAMPLE1.DAT; then you can"
  1250.                    " try the commands");
  1251.       wrscr(18, 0, "V to change the viewpoint and E to display"
  1252.                    " your results on");
  1253.         wrscr(19, 0, "the entire screen. Command H for hidden-"
  1254.                          " line removal is recommended");
  1255.       wrscr(20, 0, "next. If, after this, you want to draw a"
  1256.                    " new picture yourself, ");
  1257.       wrscr(21, 0, "then you should use command C first"
  1258.                    " to clear the screen.");
  1259.    }
  1260. }
  1261.  
  1262. static void line3(int P, int Q)
  1263. {
  1264.    float ze1, ze2, zrange=zemax-zemin+1e-15;
  1265.    int X1, Y1, X2, Y2, i1, i2, j1, j2;
  1266.    char str[10];
  1267.    static int dx[] = {0, 1, -1, 0, 0},
  1268.               dy[] = {0, 0, 0, 1, -1},
  1269.                n[] = { 5, 4, 3, 2, 1};
  1270.    screencoor(1, P, &X1, &Y1);         /* Computes xxx and yyy */
  1271.    if(zoom && fplot != NULL)
  1272.       move(xxx, yyy);
  1273.     screencoor(1, Q, &X2, &Y2);
  1274.    if(zoom && fplot !=NULL)
  1275.       draw(xxx, yyy);
  1276.    if(!zoom || bold) {
  1277.       ze1 = p[P].ze;
  1278.       ze2 = p[Q].ze;
  1279.       i1 = (int)((ze1 - zemin)/zrange *4.999);
  1280.       i2 = (int)((ze2 - zemin)/zrange *4.999);
  1281.       if(i1 < 0 || i2 < 0 | i1 > 4 || i2 > 4) {
  1282.          to_text();
  1283.          printf("i1=%d i2=%d\n", i1, i2);
  1284.          printf("P = %d\n", P);
  1285.          printf("Q = %d\n", Q);
  1286.             printf("ze1=%f ze2 = %f zemin=%f zrange=%f\n",
  1287.                   ze1, ze2, zemin, zrange);
  1288.          exit(1);
  1289.       }
  1290.       for(j1=0; j1<n[i1]; j1++)
  1291.       for(j2=0; j2<n[i2]; j2++)
  1292.       draw_line(X1+dx[j1], Y1+dy[j1], X2+dx[j2], Y2+dy[j2]);
  1293.    }
  1294.    else
  1295.         draw_line(X1, Y1, X2, Y2);
  1296.    if(numbers) {
  1297.       sprintf(str, "%d", P);
  1298.       imove(X1-2, Y1-5);
  1299.       text(str);
  1300.       sprintf(str, "%d", Q);
  1301.       imove(X2-2, Y2-5);
  1302.       text(str);
  1303.    }
  1304. }
  1305.  
  1306. static void list_faces(void)
  1307. {
  1308.    int j, i, nch, nch0, count=0, n, nchmax;
  1309.    char str[50], ch;
  1310.  
  1311.    nchmax = (X__max - margin)/8;
  1312.    for(j=0; j<nface; j++) {
  1313.       if(pface[j] == NULL) 
  1314.          continue;
  1315.       count++;
  1316.       n = pface[j][0];
  1317.       nch = 0;
  1318.       if(n<0)
  1319.          ermes("n<0 in list_faces");
  1320.       for(i=1; i<=n; i++) {
  1321.          nch0 = nch;
  1322.          nch += sprintf(str+nch, " %d", pface[j][i]);
  1323.          if(nch > nchmax) {
  1324.             str[nch0] = '\0';
  1325.             break;
  1326.          }
  1327.       }
  1328.       s2[0] = '.';
  1329.       grmes(LIN2, str);
  1330.       textXY(margin + 8*strlen(str), LIN2, s2);
  1331.       ch = query(LIN3, "OK (Y/N): ");
  1332.       if(ch == 'N') {
  1333.          farfree(pface[j]);
  1334.          pface[j] = NULL;
  1335.          display();
  1336.          if(!faces_present && (!axes || !auxlines || !numbers)) {
  1337.             axes = auxlines = numbers = 1;
  1338.             display();
  1339.          }
  1340.       }
  1341.       else if(ch != 'Y') 
  1342.          break;
  1343.    }
  1344.    if(count == 0)
  1345.       grmes(LIN2, "No faces");
  1346.    else
  1347.       grmes(LIN2, " ");
  1348.    grmes(LIN3, " ");
  1349. }
  1350.  
  1351. int matherr(struct exception *a)
  1352. {
  1353.    if(a->type == DOMAIN) {
  1354.       if(strcmp(a->name, "sqrt") == 0)
  1355.          ermes("sqrt domain error");
  1356.    }
  1357.    ermes("Floating point error");
  1358.    return(0);                    /* will not execute due to ermes */
  1359. }
  1360.  
  1361. static void mv(float x, float y, float z)
  1362. {
  1363.    int X, Y;
  1364.    double xe, ye, ze;
  1365.  
  1366.    viewing(x-0.5, y-0.5, z-0.5, &xe, &ye, &ze);
  1367.    /* xO = yO = zO = 0.5 */
  1368.    X = IX(d*xe/ze+c1);
  1369.    Y = IY(d*ye/ze+c2);
  1370.    imove(X, Y);
  1371. }
  1372.  
  1373. static char mygetch(void)
  1374. {
  1375.    char ch;
  1376.    ch = getch();
  1377.    if (ch == 3) {      /* Ctrl-C or Ctrl-Break */
  1378.       if(!in_textmode)
  1379.          to_text();
  1380.       exit(1);
  1381.    }
  1382.    char_avail = 0;
  1383.    return ch;
  1384. }
  1385.  
  1386. static void myungetch(char ch)
  1387. {
  1388.    ungetch(ch);
  1389.    char_avail = 1;
  1390. }
  1391.  
  1392.  
  1393. static void open_plotfile(void)
  1394. {
  1395.    char *p, *q, plfilnam[40];
  1396.    if(*filnam) {
  1397.       p = filnam;
  1398.       q = plfilnam;
  1399.         while(*p && *p !='.')
  1400.          *q++ = *p++;
  1401.       strcpy(q, ".plt");
  1402.    }
  1403.    else
  1404.       strcpy(plfilnam, "noname.plt");
  1405.    fplot = fopen(plfilnam, "w");
  1406.    if(fplot == NULL)
  1407.       ermes("Can't open plotfile");
  1408. }
  1409.  
  1410. static void plotaxes(int checksize)
  1411. {
  1412.    int X0, Y0, X1, Y1, X2, Y2, X3, Y3, cnt, i;
  1413.  
  1414.    if(checksize) {
  1415.       storepoint(nmax,     0.0,   0.0,   0.0);
  1416.       storepoint(nmax+1, xwmax,   0.0,   0.0);
  1417.       storepoint(nmax+2,   0.0, ywmax,   0.0);
  1418.       storepoint(nmax+3,   0.0,   0.0, zwmax);
  1419.         screencoor(0, nmax,   &X0, &Y0);
  1420.         screencoor(0, nmax+1, &X1, &Y1);
  1421.         screencoor(0, nmax+2, &X2, &Y2);
  1422.         screencoor(0, nmax+3, &X3, &Y3);
  1423.       reposition();
  1424.       inside = 1;
  1425.    }
  1426.    storepoint(nmax,     0.0,   0.0,   0.0);
  1427.    storepoint(nmax+1, xwmax,   0.0,   0.0);
  1428.    storepoint(nmax+2,   0.0, ywmax,   0.0);
  1429.    storepoint(nmax+3,   0.0,   0.0, zwmax);
  1430.     screencoor(1, nmax,   &X0, &Y0);
  1431.     screencoor(1, nmax+1, &X1, &Y1);
  1432.     screencoor(1, nmax+2, &X2, &Y2);
  1433.     screencoor(1, nmax+3, &X3, &Y3);
  1434.    for(i=nmax; i<nmax+4; i++)
  1435.       p[i].inuse = 0;
  1436.    if(checksize && !inside) {
  1437.       to_text();
  1438.       printf("not inside in plotaxes\n");
  1439.       printf("d=%f c1=%f c2=%f\n", d, c1, c2);
  1440.       printf("Xvp_min=%f Xvp_max=%f Yvp_min=%f Yvp_max=%f\n",
  1441.               Xvp_min, Xvp_max, Yvp_min, Yvp_max);
  1442.       for(cnt=nmax; cnt<nmax+4; cnt++) {
  1443.          printf("cnt=%d xe=%f ye=%f ze=%f X=%d Y=%d\n",
  1444.                  cnt, p[cnt].xe, p[cnt].ye, p[cnt].ze,
  1445.                       IX(d*p[cnt].xe/p[cnt].ze+c1),
  1446.                  IY(d*p[cnt].ye/p[cnt].ze+c2));
  1447.       }
  1448.       exit(0);
  1449.    }
  1450.    imove(X0, Y0); idraw(X1, Y1); text("x");
  1451.    imove(X0, Y0); idraw(X2, Y2); text("y");
  1452.    imove(X0, Y0); idraw(X3, Y3); text("z");
  1453. }
  1454.  
  1455. static void plotpoint(int i, int Bold)
  1456. {
  1457.    char str[30];
  1458.    int X, Y, Xxy0, Yxy0, cnt;
  1459.  
  1460.    inside = 1;
  1461.    for(cnt=0;  cnt<2; cnt++) {
  1462.       screencoor(1, i, &X, &Y);
  1463.       if(auxlines) {
  1464.          storepoint(nmax+6, p[i].xw, p[i].yw, 0.0);
  1465.             screencoor(1, nmax+6, &Xxy0, &Yxy0);
  1466.          p[nmax+6].inuse = 0;
  1467.       }
  1468.       if(inside)
  1469.          break;
  1470.       else {
  1471.          reposition();
  1472.          display();
  1473.       }
  1474.    }
  1475.    if(cnt == 2)
  1476.       ermes("cnt = 2 in plotpoint");
  1477.    if(auxlines)
  1478.         draw_line(Xxy0, Yxy0, X, Y);
  1479.    dot(X, Y);
  1480.    if(numbers) {
  1481.       sprintf(str, "%d", i);
  1482.       imove(X-2, Y-5);
  1483.       text(str);
  1484.    }
  1485.    else if(nface == 0 || Bold) {
  1486.       dot(X-1, Y-1);
  1487.       dot(X  , Y-1);
  1488.       dot(X+1, Y-1);
  1489.       dot(X-1, Y  );
  1490.       dot(X+1, Y  );
  1491.       dot(X-1, Y+1);
  1492.       dot(X  , Y+1);
  1493.       dot(X+1, Y+1);
  1494.    }
  1495. }
  1496.  
  1497. static void plotsph(float rho, float theta, float phi, int down)
  1498. {
  1499.    float x, y, z, rcosphi, rsinphi, costh, sinth;
  1500.  
  1501.    theta = theta * PIdiv180;
  1502.    phi   = phi   * PIdiv180;
  1503.    rcosphi = rho * cos(phi);
  1504.    rsinphi = rho * sin(phi);
  1505.    costh   = cos(theta);
  1506.    sinth   = sin(theta);
  1507.    x = rsinphi * costh;
  1508.    y = rsinphi * sinth;
  1509.    z = rcosphi;
  1510.  
  1511.    if(down)
  1512.       dw(x, y, z);
  1513.    else
  1514.       mv(x, y, z);
  1515. }
  1516.  
  1517. static void points(void)
  1518. {
  1519.    char str[50];
  1520.    int i;
  1521.    float x, y, z;
  1522.  
  1523.    grmes(LIN2, "n x y z:");
  1524.    getstr(margin, LIN3, str);
  1525.    if(sscanf(str,"%d %f %f %f", &i, &x, &y, &z) != 4 || i <= 0) {
  1526.       grmes(LIN2, "Invalid number format");
  1527.       points_entering = 0;
  1528.       return;
  1529.    }
  1530.    check_alloc(i);
  1531.    if(i >= nmax)
  1532.       nmax = i+1;
  1533.    if(storepoint(i, x, y, z)) {
  1534.       checkall();
  1535.       display();
  1536.    }
  1537.    plotpoint(i, 1);
  1538.    modified = 1;
  1539. }
  1540.  
  1541. static void pressanykey(char *str)
  1542. {
  1543.    grmes(LIN2, str);
  1544.    grmes(LIN3, "Press any key ...");
  1545.    mygetch();
  1546. }
  1547.  
  1548. static char query(int line, char *s)
  1549. {
  1550.    int pos;
  1551.    char ch;
  1552.  
  1553.    grmes(line, s);
  1554.    pos = margin + 8*strlen(s);
  1555.    textcursor(pos, line);
  1556.    ch = mygetch();
  1557.    s2[0] = ch;
  1558.    ch = toupper(ch);
  1559.    textXY(pos, line, s2);
  1560.    return ch;
  1561. }
  1562.  
  1563. static void rdfile(int normal)
  1564. {
  1565.    FILE *fp;
  1566.     int ch, i_old=0, base, lowlimit, i, n, drawn, X, Y;
  1567.    float x, y, z, i_float;
  1568.    char str[40];
  1569.  
  1570.    modified = 0;  /* File and data structure identical! */
  1571.    if(normal) {
  1572.       if(object_present) {
  1573.          ch = query(LIN2, "Clear screen (Y/N) ");
  1574.             if(ch == 'Y' || ch == 'y')
  1575.             clear();
  1576.          else
  1577.             modified = 1;
  1578.       }
  1579.       if(kbhit())
  1580.          getch();
  1581.       grmes(LIN2, "Input file: ");
  1582.       getstr(margin, LIN3, filnam);
  1583.    }
  1584.     fp = fopen(filnam, "r");
  1585.    if(fp == NULL) {
  1586.       grmes(LIN2, "Can't open file");
  1587.       return;
  1588.    }
  1589.    grmes(LIN3, "Please wait ...");
  1590.  
  1591.    base = nmax-1;
  1592.    inside = 1;
  1593.    lowlimit = 32767;
  1594.     while(fscanf(fp,"%f %f %f %f", &i_float, &x, &y, &z) == 4) {
  1595.         if(getc(fp) != '\n') {
  1596.          grmes(LIN2, "Wrong file format.");
  1597.          grmes(LIN3, "Use n x y z");
  1598.          fclose(fp);
  1599.          return;
  1600.       }
  1601.       i = (int)(i_float + 0.001);
  1602.       if(i <= 0) {
  1603.          grmes(LIN3, "Point nr. not positive");
  1604.          fclose(fp);
  1605.          return;
  1606.       }
  1607.       i += base;
  1608.       if(i < lowlimit)
  1609.          lowlimit = i;
  1610.       check_alloc(i);
  1611.       if(i >= nmax)
  1612.          nmax = i + 1;
  1613.       storepoint( i, x, y, z);
  1614.       screencoor(0, i, &X, &Y);
  1615.    }
  1616.    if(base && lowlimit < 32767) {
  1617.       grmes(LIN1, "Range of new points:");
  1618.       sprintf(str, "%d-%d", lowlimit, nmax-1);
  1619.       pressanykey(str);
  1620.    }
  1621.    inside = 1;
  1622.    for(i=base; i<nmax; i++)
  1623.       if(p[i].inuse)
  1624.          screencoor(1, i, &X, &Y);
  1625.    if(!inside)
  1626.       reposition();
  1627.    do ch = getc(fp); while (isspace(ch));
  1628.    axes = numbers = (ch != 'F' && ch != 'f');
  1629.    if(!axes) auxlines = 0;
  1630.    display();
  1631.    if(!axes) {        /* That is, if there are faces */
  1632.       do ch = getc(fp); while (ch != '\n' && ch != EOF);
  1633.       /* Skip input line with keyword 'faces' */
  1634.       while(fscanf(fp, "%d", &i) == 1) {
  1635.          if((pface[nface] = (int *)farcalloc(5, sizeof(int))) == NULL)
  1636.             ermes("Not enough memory");
  1637.          n = 0;
  1638.          while(1) {
  1639.             if(n > 0) {
  1640.                if(fscanf(fp, "%d", &i) <=0)
  1641.                   break;
  1642.             }
  1643.             n++;
  1644.             drawn = i >= 0;
  1645.             i = abs(i) + base;
  1646.             if(p[i].inuse == 0) {
  1647.                sprintf(str, "Undef. point: %6d", i);
  1648.                grmes(LIN3, str);
  1649.                fclose(fp);
  1650.                return;
  1651.             }
  1652.             if(n > 1 && drawn)
  1653.                line3(i_old, i);
  1654.             i_old = i;
  1655.             if(n > 4) {
  1656.                if((pface[nface] = (int *) 
  1657.                   farrealloc(pface[nface], (n+1) * sizeof(int))) == NULL) 
  1658.                   ermes("Not enough memory");
  1659.             }
  1660.             pface[nface][n] = (drawn ? i : -i);
  1661.          }
  1662.          ch = getc(fp);
  1663.          if(ch != '#' && ch != '.') {
  1664.             grmes(LIN3, "Period or # expected");
  1665.             fclose(fp);
  1666.             return;
  1667.          }
  1668.          if(n > 2) {
  1669.             i = pface[nface][1];
  1670.             if(i >= 0)
  1671.                line3(i_old, i);
  1672.          }
  1673.          pface[nface][0] = n;
  1674.          nface++;
  1675.          if(nface == MAXFACES)
  1676.             ermes("Too many faces #2");
  1677.       }
  1678.       ch = getc(fp);
  1679.    }
  1680.    else
  1681.       numbers = 1;
  1682.    if(ch != EOF)
  1683.       grmes(LIN2, "Incorrect file format");
  1684.    else
  1685.       grmes(LIN2, " ");
  1686.       grmes(LIN3, " ");
  1687.       fclose(fp);
  1688. }
  1689.    
  1690. static int rdnumber(int *p)
  1691. /* called only in 'faces' and 'transform' */
  1692. {
  1693.    int i, neg, d, i0;
  1694.    char ch;
  1695.  
  1696.    *p = 0;
  1697.    do ch = getch1(); while (isspace(ch));
  1698.    neg = ch == '-';
  1699.     if(neg || ch == '+')
  1700.       ch = getch1();
  1701.    if(!isdigit(ch))
  1702.       return 0;
  1703.    i = ch - '0';
  1704.    while(ch = getch1(), isdigit(ch)) {
  1705.       d = ch - '0';
  1706.       i0 = i;
  1707.       i = 10* i + d;
  1708.         if(i < i0) {
  1709.          grmes(LIN3, "Too many digits");
  1710.          return 0;
  1711.       }
  1712.    }
  1713.     *p = (neg ? -i: i);
  1714.    if(bufposition > 0)
  1715.       bufposition--;
  1716.     /* i.e. myungetch1(ch) */
  1717.    return 1;
  1718. }
  1719.  
  1720. static int rdoldnr(int *q) 
  1721. {
  1722.    int code, i, pnr;
  1723.    code = rdnumber(&i);
  1724.    pnr = abs(i);
  1725.    *q = i;
  1726.    if (code == 0 || pnr >= nmax || pnr && p[pnr].inuse == 0) {
  1727.       grmes(LIN2, "Incorrect point nr.");
  1728.       mygetch();
  1729.       return 0;
  1730.    }
  1731.    else
  1732.       return 1;
  1733. }
  1734.  
  1735. static void reposition(void)
  1736. /* Requires xwmin etc. to be correct */
  1737. {
  1738.    float Xrange, Yrange, fx, fy, Xcenter, Ycenter,
  1739.       x1, y1, z1, q=0.4, xtol, ytol, ztol;
  1740.    int i, X, Y;
  1741.  
  1742.    x1 = 0.5 * (xwmin + xwmax);
  1743.    y1 = 0.5 * (ywmin + ywmax);
  1744.    z1 = 0.5 * (zwmin + zwmax);
  1745.    xtol  =q * (xwmax - xwmin);
  1746.    ytol  =q * (ywmax - ywmin);
  1747.    ztol  =q * (zwmax - zwmin);
  1748.    if(fabs(xO - x1) > xtol ||
  1749.       fabs(yO - y1) > ytol ||
  1750.       fabs(zO - z1) > ztol) {
  1751.       grmes(LIN3, "Please wait ...");
  1752.       xO = x1;
  1753.       yO = y1;
  1754.       zO = z1;
  1755.       newcentralpoint = 1;       /* See command 'E' */
  1756.       fresh();
  1757.       for(i=0; i<nmax+6; i++) {  /* See 'clear' and 'cursor' */
  1758.          if(p[i].inuse) {
  1759.             storepoint(i, p[i].xw, p[i].yw, p[i].zw);
  1760.             screencoor(0, i, &X, &Y);
  1761.             /* compute new xmin etc. */
  1762.             if(axes) {
  1763.                storepoint(nmax+6, p[i].xw,    0.0,    0.0);
  1764.                screencoor(0, nmax+6, &X, &Y);
  1765.                storepoint(nmax+6, 0.0    ,p[i].yw,    0.0);
  1766.                screencoor(0, nmax+6, &X, &Y);
  1767.                storepoint(nmax+6, 0.0    ,    0.0,p[i].zw);
  1768.                screencoor(0, nmax+6, &X, &Y);
  1769.             }
  1770.             if(auxlines) {
  1771.                storepoint(nmax+6, p[i].xw,p[i].yw,     0.0);
  1772.                screencoor(0, nmax+6, &X, &Y);
  1773.             }
  1774.          }
  1775.       }
  1776.       p[nmax+6].inuse = 0;
  1777.       grmes(LIN3, " ");
  1778.    }
  1779.    Xrange = xmax - xmin;
  1780.    Yrange = ymax - ymin;
  1781.    if(Xrange < 1e-12) Xrange = 1e-12;
  1782.    if(Yrange < 1e-12) Yrange = 1e-12;
  1783.    Xcenter = 0.5 * (xmin + xmax);
  1784.    Ycenter = 0.5 * (ymin + ymax);
  1785.    fx = Xvp_range/Xrange;
  1786.    fy = Yvp_range/Yrange;
  1787.    d = (fx < fy ? fx : fy);
  1788.    if(!zoomin)
  1789.       d *=0.85;
  1790.    /* Provide some space for new points */
  1791.    c1 = Xvp_center - d*Xcenter;
  1792.    c2 = Yvp_center - d*Ycenter;
  1793. }
  1794.  
  1795. static void screencoor(int mode, int i, int *pX, int *pY)
  1796. {
  1797.    double xe, ye, ze, xs, ys;
  1798.  
  1799.    xe = p[i].xe;
  1800.    ye = p[i].ye;
  1801.    ze = p[i].ze;
  1802.    xs = xe/ze;
  1803.    ys = ye/ze;
  1804.  
  1805.    if(xs < xmin) xmin = xs;
  1806.    if(xs > xmax) xmax = xs;
  1807.    if(ys < ymin) ymin = ys;
  1808.    if(ys > ymax) ymax = ys;
  1809.    if(mode == 0)
  1810.       return;
  1811.    xxx = d*xs + c1;
  1812.    yyy = d*ys + c2;
  1813.    if(!zoomin) {
  1814.       if(xxx < Xvp_min || xxx > Xvp_max || 
  1815.          yyy < Yvp_min || xxx > Yvp_max) inside = 0;
  1816.    }
  1817.    *pX = IX(xxx);
  1818.     *pY = IY(yyy);
  1819. }
  1820.  
  1821. static void show(char c)
  1822. {
  1823.    if(!zoomin) {
  1824.       s2[0] = c;
  1825.       textXY(margin + 72, LIN1, s2);
  1826.    }
  1827. }
  1828.  
  1829. static int storepoint(int i, float xw, float yw, float zw)
  1830. {
  1831.    int oldpoint = 0;
  1832.    double xe, ye, ze;
  1833.  
  1834.    if(i<nmax && p[i].inuse)
  1835.       oldpoint = 1;
  1836.    p[i].xw = xw;
  1837.    p[i].yw = yw;
  1838.    p[i].zw = zw;
  1839.  
  1840.    if(p[i].inuse == 0)
  1841.       p[i].inuse = 1;
  1842.    viewing(xw-xO, yw-yO, zw-zO, &xe, &ye, &ze);
  1843.  
  1844.    p[i].xe = xe;
  1845.    p[i].ye = ye;
  1846.    p[i].ze = ze;
  1847.  
  1848.    if(xw < xwmin ) xwmin = xw;
  1849.    if(xw > xwmax ) xwmax = xw;
  1850.    if(yw < ywmin ) ywmin = yw;
  1851.    if(yw > ywmax ) ywmax = yw;
  1852.    if(zw < zwmin ) zwmin = zw;
  1853.    if(zw > zwmax ) zwmax = zw;
  1854.     if(ze < zemin ) zemin = ze;
  1855.     if(ze > zemax ) zemax = ze;
  1856.    if(i < nmax)
  1857.       object_present = 1;
  1858.    return oldpoint;
  1859.    /* storepoint normally returns 0;
  1860.       it returns 1 if point i already exists */
  1861. }
  1862.  
  1863.  
  1864. static void textcursor(int col, int line)
  1865. {
  1866.    static char underline[2] = "_", dum[2]=" ";
  1867.    int j;
  1868.  
  1869.    if(char_avail)
  1870.       return;
  1871.    do {
  1872.       j=100;
  1873.       do textXY(col, line, underline);
  1874.             while (--j && !kbhit());
  1875.       j=200;
  1876.       do textXY(col, line, dum);
  1877.          while (--j && !kbhit());
  1878.    }
  1879.    while (!kbhit());
  1880. }
  1881.  
  1882. static void transform(void)
  1883. {
  1884.    char ch, str[30];
  1885.     int P=-1, Q=-1, R=-1, Pabs=-1, Qabs = -1, Rabs=-1,
  1886.          A, B, Aabs, Babs, i, i1, duplicate, refl=0, tmp,
  1887.        *pnum, j, j1, n, k, k1, freepos, m, mabs,
  1888.        lowest, highest;
  1889.    double x, y, z, a ,b, c, d, h,
  1890.        xP, xQ, xR, yP, yQ, yR, zP, zQ, zR,
  1891.        len, fact;
  1892.    float alpha=0.0, Sx=1.0, Sy=1.0, Sz=1.0,
  1893.        xC, yC, zC, C1, C2, C3,
  1894.        xlowest=1.0, xhighest, x1=0.0, y1=0.0, z1=0.0;
  1895.  
  1896.    while(nmax > 0 && p[nmax-1].inuse == 0) nmax--;
  1897.    duplicate = (query(LIN2, "Move/Copy? (M/C) ") == 'C');
  1898.    enquire(LIN2, "Lower bound: ", &xlowest);
  1899.    lowest = (int)(xlowest + 0.1);
  1900.     if(lowest < 1) 
  1901.       lowest = 1;
  1902.    xhighest = nmax - 1;
  1903.    enquire(LIN3, "Upper bound: ", &xhighest);
  1904.    highest = (int)(xhighest + 0.1);
  1905.    if(highest >= nmax) 
  1906.       highest = nmax - 1;
  1907.    if(duplicate) {
  1908.       freepos = nmax;
  1909.       check_alloc(nmax + highest - lowest);
  1910.    }
  1911.    grmes(LIN3, " ");
  1912.    ch = query(LIN2, "Rotation? (Y/N) ");
  1913.    if(ch == 'Y') {
  1914.       grmes(LIN1, "Rotation about PQ.");
  1915.       grmes(LIN2, "Point nrs. P and Q:");
  1916.       bufposition = -1;
  1917.       if(!rdoldnr(&P) || !rdoldnr(&Q))
  1918.          return;
  1919.       Pabs = abs(P);
  1920.       Qabs = abs(Q);
  1921.       x = p[Pabs].xw;
  1922.       y = p[Pabs].yw;
  1923.       z = p[Pabs].zw;
  1924.       x1= p[Qabs].xw;
  1925.       y1= p[Qabs].yw;
  1926.       z1= p[Qabs].zw;
  1927.       enquire(LIN2, "Angle in degrees:", &alpha);
  1928.       alpha = alpha * PIdiv180;
  1929.       initrotate(x, y, z, x1-x, y1-y, z1-z, alpha);
  1930.       for(i=lowest; i<=highest; i++)
  1931.       if(p[i].inuse && (P > 0 || i != Pabs) &&
  1932.                               (Q > 0 || i != Qabs)) {
  1933.          rotate(p[i].xw, p[i].yw, p[i].zw, &x, &y, &z);
  1934.          if(duplicate) {
  1935.             i1 = freepos++;
  1936.             p[i1].inuse = 1;
  1937.             p[i].inuse = i1;
  1938.          }
  1939.          else
  1940.             i1 = i;
  1941.          p[i1].xw = x;
  1942.          p[i1].yw = y;
  1943.          p[i1].zw = z;
  1944.       }
  1945.    }
  1946.    else {
  1947.       ch = query(LIN2, "Translation? (Y/N) ");
  1948.       if(ch == 'Y') {
  1949.          grmes(LIN2, " ");
  1950.          if(query(LIN1, "Shift vector? (Y/N) ") != 'Y') {
  1951.             enquire(LIN1, "delta x = ", &x1);
  1952.             enquire(LIN2, "delta y = ", &y1);
  1953.             enquire(LIN3, "delta z = ", &z1);
  1954.          }
  1955.          else {
  1956.             grmes(LIN1, "AB is shift vector");
  1957.             grmes(LIN2, "Point nrs. A and B:");
  1958.             bufposition = -1;
  1959.             if(!rdoldnr(&A) || !rdoldnr(&B))
  1960.                return;
  1961.             Aabs = abs(A);
  1962.             Babs = abs(B);
  1963.             x = p[Aabs].xw;
  1964.             y = p[Aabs].yw;
  1965.             z = p[Aabs].zw;
  1966.             x1 = p[Babs].xw - x;
  1967.             y1 = p[Babs].yw - y;
  1968.             z1 = p[Babs].zw - z;
  1969.          }
  1970.  
  1971.          for(i=lowest; i<=highest; i++)
  1972.          if (p[i].inuse && (A > 0 || i != Aabs) && (B > 0 || i != Babs)) {
  1973.             if(duplicate) {
  1974.                i1 = freepos++;
  1975.                p[i1].inuse = 1;
  1976.                p[i].inuse = i1;
  1977.             }
  1978.             else
  1979.                i1 = i;
  1980.             p[i1].xw = p[i].xw + x1;
  1981.             p[i1].yw = p[i].yw + y1;
  1982.             p[i1].zw = p[i].zw + z1;
  1983.          }
  1984.       }
  1985.       else {
  1986.          ch = query(LIN2, "Scaling? (Y/N) ");
  1987.          if(ch == 'Y') {
  1988.             if(query(LIN2, "Uniform? (Y/N) ") == 'Y') {
  1989.                enquire(LIN3, "Sx=Sy=Sz = ", &Sx);
  1990.                Sy = Sz = Sx;
  1991.             }
  1992.             else {
  1993.                grmes(LIN2, " ");
  1994.                enquire(LIN1, "Sx = ", &Sx);
  1995.                enquire(LIN2, "Sy = ", &Sy);
  1996.                enquire(LIN3, "Sz = ", &Sz);
  1997.             }
  1998.             while(1) {
  1999.                grmes(LIN1, "Fixed point:");
  2000.                grmes(LIN2, "Center (C), Origin (O)");
  2001.                ch = query(LIN3, "or a Vertex (V): ");
  2002.                if(ch == 'C') {
  2003.                   checkall();
  2004.                   xC = xO;
  2005.                   yC = yO;
  2006.                   zC = zO;
  2007.                }
  2008.                else if(ch == 'O' || ch == '0')
  2009.                   xC = yC = zC = 0.0;
  2010.                else if (ch == 'V') {
  2011.                   grmes(LIN2, "Point number: ");
  2012.                   bufposition = -1;
  2013.                   if(!rdoldnr(&P))
  2014.                      return;
  2015.                   Pabs = abs(P);
  2016.                   xC = p[Pabs].xw;
  2017.                   yC = p[Pabs].yw;
  2018.                   zC = p[Pabs].zw;
  2019.                }
  2020.                else
  2021.                   continue;
  2022.                break;
  2023.             }
  2024.             C1 = xC * (1.0 - Sx);
  2025.             C2 = yC * (1.0 - Sy);
  2026.             C3 = zC * (1.0 - Sz);
  2027.             for(i=lowest; i<=highest; i++)
  2028.             if(p[i].inuse && (P > 0 || i != Pabs)) {
  2029.                if(duplicate) {
  2030.                   i1 = freepos++;
  2031.                   p[i1].inuse = 1;
  2032.                   p[i].inuse = i1;
  2033.                }
  2034.                else
  2035.                   i1 = i;
  2036.                p[i1].xw = Sx * p[i].xw + C1;
  2037.                p[i1].yw = Sy * p[i].yw + C2;
  2038.                p[i1].zw = Sz * p[i].zw + C3;
  2039.             }
  2040.          }
  2041.          else {
  2042.             ch = query(LIN2, "Reflection? (Y/N) ");
  2043.             if(ch == 'Y') {
  2044.                grmes(LIN1, "PQR is plane of refl.");
  2045.                     grmes(LIN2, "Point nrs. P, Q, R:");
  2046.                bufposition = -1;
  2047.                     refl = 1;
  2048.                if(!rdoldnr(&P) || !rdoldnr(&Q) || !rdoldnr(&R))
  2049.                   return;
  2050.                Pabs = abs(P);
  2051.                Qabs = abs(Q);
  2052.                Rabs = abs(R);
  2053.                xP = p[Pabs].xw;
  2054.                yP = p[Pabs].yw;
  2055.                zP = p[Pabs].zw;
  2056.                xQ = p[Qabs].xw;
  2057.                yQ = p[Qabs].yw;
  2058.                zQ = p[Qabs].zw;
  2059.                xR = p[Rabs].xw;
  2060.                yR = p[Rabs].yw;
  2061.                zR = p[Rabs].zw;
  2062.                     a = yP*zQ + zP*yR + yQ*zR - yP*zR - zP*yQ - zQ*yR;
  2063.                b = xP*zQ + zP*xR + xQ*zR - xP*zR - zP*xQ - zQ*xR;
  2064.                c = xP*yQ + yP*xR + xQ*yR - xP*yR - yP*xQ - yQ*xR;
  2065.                     len = sqrt(a*a + b*b + c*c);
  2066.                if(len == 0.0)
  2067.                         len = 1e-15;
  2068.                     a /= len;
  2069.                     b /= len;
  2070.                     c /= len;
  2071.                     d = a*xP + b*yP + c*zP;
  2072.                for(i=lowest; i<=highest; i++)
  2073.                if(p[i].inuse &&
  2074.                   (P > 0 || i != Pabs) &&
  2075.                   (Q > 0 || i != Qabs) &&
  2076.                   (R > 0 || i != Rabs)) {
  2077.                   if(duplicate) {
  2078.                      i1 = freepos++;
  2079.                      p[i1].inuse = 1;
  2080.                      p[i].inuse = i1;
  2081.                   }
  2082.                   else
  2083.                      i1 = i;
  2084.                   x = p[i].xw;
  2085.                   y = p[i].yw;
  2086.                   z = p[i].zw;
  2087.                   h = a*x + b*y + c*z;
  2088.                   fact = 2.0 * (d - h);
  2089.                   p[i1].xw = x + fact * a;
  2090.                   p[i1].yw = y + fact * b;
  2091.                   p[i1].zw = z + fact * c;
  2092.                }
  2093.             }
  2094.             else {
  2095.                grmes(LIN2, " ");
  2096.                return;
  2097.             }
  2098.          }
  2099.       }
  2100.    }
  2101.    if(duplicate) {
  2102.       grmes(LIN1, "Range of new points:");
  2103.       sprintf(str, "%d-%d", nmax, freepos-1);
  2104.       pressanykey(str);
  2105.       nmax = freepos;
  2106.    }
  2107.    grmes(LIN3, "Please wait ...");
  2108.     modified = 1;
  2109.    checkall();
  2110.    while(nface > 0 && pface[nface-1] == NULL) nface--;
  2111.    if(duplicate) {
  2112.       if(2*nface >= MAXFACES) {
  2113.          grmes(LIN3, "Too many faces #3");
  2114.          getch();
  2115.          display();
  2116.          return;
  2117.       }
  2118.       freepos = nface;
  2119.       for(j=0; j<nface; j++) {
  2120.          if(pface[j] == NULL)
  2121.             continue;
  2122.          j1 = freepos++;
  2123.          pface[j1] = NULL;
  2124.          n = pface[j][0];
  2125.          if(n<0)
  2126.             ermes("n<0 in transform");
  2127.          if((pface[j1] = (int *)farcalloc(n+1, sizeof(int))) == NULL)
  2128.             ermes("Not enough memory");
  2129.          pface[j1][0] = n;
  2130.             for(k=1; k<=n; k++) {
  2131.             k1 = (refl ? (n > 3 ? (k < 4 ? 4-k : 4+n-k) : n+1-k) :k);
  2132.             m = pface[j][k1];
  2133.             mabs = abs(m);
  2134.             if(mabs < lowest || mabs > highest)
  2135.                break;
  2136.             pface[j1][k] = 
  2137.             (mabs == Pabs && P < 0 ||
  2138.              mabs == Qabs && Q < 0 ||
  2139.              mabs == Rabs && R < 0 
  2140.              ? m : (m < 0 ? -p[mabs].inuse : p[m].inuse));
  2141.           }
  2142.           if(mabs < lowest || mabs > highest) {
  2143.              farfree(pface[j1]);
  2144.              freepos--;
  2145.           }
  2146.        }
  2147.        nface = freepos;
  2148.     }
  2149.     else if(refl) {  /* Invert the orientation of all faces */
  2150.       for(j=0; j<nface; j++) {
  2151.          if(pface[j] == NULL)
  2152.             continue;
  2153.          n = pface[j][0];
  2154.          if(n < 3)
  2155.             continue;
  2156.          pnum = pface[j];
  2157.          tmp = pnum[1];
  2158.          pnum[1] = pnum[3];
  2159.          pnum[3] = tmp;
  2160.          k1 = (n - 3)/2;
  2161.             for(k=1; k<=k1; k++) {
  2162.             tmp = pnum[3+k];
  2163.             pnum[3+k] = pnum[n+1-k];
  2164.             pnum[n+1-k] = tmp;
  2165.          }  /* E.g. old: 1 2 3 4 5 6 7 8. */
  2166.       }     /*      new: 3 2 1 8 7 6 5 4. */
  2167.    }        /* (Any vertex except 2 may become concave. */
  2168.    display();
  2169. }
  2170.  
  2171. static void viewing(float x, float y, float z,
  2172.                      double *pxe, double *pye, double *pze)
  2173. {
  2174.    *pxe = v11*x + v21*y;
  2175.    *pye = v12*x + v22*y + v32*z;
  2176.    *pze = v13*x + v23*y + v33*z + v43;
  2177.    if(*pze < EPS)
  2178.       ermes("Please use greater value of rho");
  2179. }
  2180.        
  2181. static void wrfile(void)
  2182. {
  2183.    int i, j, n, k;
  2184.    char ch;
  2185.    FILE *fp;
  2186.  
  2187.    grmes(LIN2, "Output file: ");
  2188.    if(kbhit())
  2189.       getch();
  2190.    if(*filnam)
  2191.       grmes(LIN3, filnam);
  2192.     textcursor(margin + 8*strlen(filnam)+8, LIN3);
  2193.    if(ch = mygetch(), ch != '\n' && ch != '\r') {
  2194.       ungetch(ch);
  2195.       getstr(margin, LIN3, filnam);
  2196.    }
  2197.    if(*filnam == '\0' || (fp = fopen(filnam, "w")) == NULL) {
  2198.       grmes(LIN3, "Can't poen file");
  2199.       return;
  2200.    }
  2201.    for(i=0; i<nmax; i++)
  2202.    if(p[i].inuse)
  2203.       fprintf(fp, "%d %f %f %f\n", i, p[i].xw, p[i].yw, p[i].zw);
  2204.    if(nface > 0) {
  2205.       fprintf(fp, "Faces:\n");
  2206.       for(j=0; j<nface; j++) {
  2207.          if(pface[j] == NULL)
  2208.             continue;
  2209.          n = pface[j][0];
  2210.          if(n < 0)
  2211.             ermes("n<0 in wrfile");
  2212.          for(k=1; k<=n; k++)
  2213.             fprintf(fp, " %d", pface[j][k]);
  2214.          fprintf(fp, ".\n");
  2215.       }
  2216.    }
  2217.    grmes(LIN2, " ");
  2218.    grmes(LIN3, " ");
  2219.    fclose(fp);
  2220.    modified = 0;     /* File and data structure identical */
  2221. }
  2222.  
  2223. static void zoom(int code)
  2224. /* zoom can be called after initgr */
  2225. {
  2226.    if(code) {     /* 1 = large, 0 = small */
  2227.       Xvp_min = 0.25;
  2228.       Xvp_max = x_max - 0.25;
  2229.       Yvp_min = 0.4;
  2230.       Yvp_max = y_max - 0.4;
  2231.    }
  2232.    else {
  2233.       Xvp_min = 0.25;
  2234.       Xvp_max = 6.3;
  2235.       Yvp_min = 0.4;
  2236.       Yvp_max = 6.7;
  2237.    }     /* zoom(0) will not be called when pridim = 1   */
  2238.          /* so we have x_max = 10.0, y_max = 7.0         */
  2239.    zoomin = code;
  2240.    Xvp_range = Xvp_max - Xvp_min;
  2241.    Yvp_range = Yvp_max - Yvp_min;
  2242.    Xvp_center = 0.5*(Xvp_max + Xvp_min);
  2243.    Yvp_center = 0.5*(Yvp_max + Yvp_min);
  2244. }
  2245.  
  2246.       
  2247.    
  2248.          
  2249.